<?php
/*
 * 地区函数
 * @package    system
 * @author     Mark
 * @copyright  Copyright (c) 2013 ixdcw team
 * @version    $Id: f36863f5adc86b08f28a09101f354a419a312d00 $
 */
defined('IN_IXDCW') or exit('Access Denied');
/**
 * Class Area
 */
class Area {

	const AREA_CHINA = 3421;
	const AREA_FOREIGN = 3418;
	const AREA_ALL = 0;

	/**
	 * IP 转换为分站ID
	 * @param $ip 需要转换的IP
	 * @return int  返回分站的ID
	 */
	public static function ip2cityid($ip) {
		global $db;
		$areaname = self::ip2area($ip);
		$table    = Table::name(Table::NAME_CITY);
		$result   = $db->query("SELECT * FROM {$table}");
		while ($r = $db->fetchArray($result)) {
			if (preg_match("/" . $r['name'] . ($r['iparea'] ? '|' . $r['iparea'] : '') . "/i", $areaname)) {
				return $r['areaid'];
			}
		}
		return 0;
	}

	/**
	 * 根据地区名称返回地区ID
	 * @param       $areaName
	 * @param       $split//分隔符
	 * @param array $AREA
	 * @return int
	 */
	public static function area2id($areaName, $split='0',$AREA = array()) {
		global $db;
		$areaid = '3421';
		$table = Table::name(Table::NAME_AREA);

		if (!$AREA) {
			$AREA = $db->getAll("select * from $table order by LENGTH(arrparentid) DESC");
		}

		// 精准匹配
		foreach ($AREA as $area) {
			if ($area['areaname'] == $areaName) {
				return $area['areaid'];
			}
		}

		//逐级匹配
		if($split != '0'){
			$areaName = explode($split,$areaName);
			foreach($areaName as $v){
				foreach ($AREA as $area) {
					if (preg_match("/" . $area['areaname'] . "/i", $v)) {
						$areaid = $area['areaid'];
						$areaname = $area['areaname'];
						$AREA = $db->getAll("select * from $table where areaid in (".$area['arrchildid'].")");
						if($area['areaid'] == $area['arrchildid']){
							return $area['areaid'];
						}
					}
				}
				if (!preg_match("/" . $areaname . "/i", $v)){return $areaid;}
			}
		}

		// 模糊匹配
		foreach ($AREA as $area) {
			if (preg_match("/" . $areaName . "/i", $area['areaname'])) {
				return $area['areaid'];
			}
		}

		// 再次模糊
		foreach ($AREA as $area) {
			if (preg_match("/" . $area['areaname'] . "/i", $areaName)) {
				return $area['areaid'];
			}
		}

		return 0;
	}

	/**
	 * IP转换为地区
	 * 124.23.225.125 => 陕西省 广电网
	 * @param $ip
	 * @return array|string
	 */
	public static function ip2area($ip) {
		$area = '';
		if (Utils::isIp($ip)) {
			$tmp = explode('.', $ip);
			if ($tmp[0] == 10 || $tmp[0] == 127 || ($tmp[0] == 192 && $tmp[1] == 168) || ($tmp[0] == 172 && ($tmp[1] >= 16 && $tmp[1] <= 31))) {
				$area = 'LAN';
			} elseif ($tmp[0] > 255 || $tmp[1] > 255 || $tmp[2] > 255 || $tmp[3] > 255) {
				$area = 'Unkonw';
			} else {
				$area = self::_ip2area($ip);
			}
		}
		$area = Str::convert($area, 'gbk', DT_CHARSET);
		return $area;
	}

	/**
	 * IP转换为地区
	 * 124.23.225.125 => 陕西省 广电网
	 * @param $ip
	 * @return array|mixed|string
	 */
	private static function _ip2area($ip) {
		if (is_file(DT_ROOT . '/file/ipdata/wry.dat')) {
			$ipdatafile = DT_ROOT . '/file/ipdata/wry.dat';
			if (!$fd = @fopen($ipdatafile, 'rb')) return 'Invalid IP data file';
			$ip    = explode('.', $ip);
			$ipNum = $ip[0] * 16777216 + $ip[1] * 65536 + $ip[2] * 256 + $ip[3];
			if (!($DataBegin = fread($fd, 4)) || !($DataEnd = fread($fd, 4))) return '';
			@$ipbegin = implode('', unpack('L', $DataBegin));
			if ($ipbegin < 0) $ipbegin += pow(2, 32);
			@$ipend = implode('', unpack('L', $DataEnd));
			if ($ipend < 0) $ipend += pow(2, 32);
			$ipAllNum = ($ipend - $ipbegin) / 7 + 1;
			$BeginNum = $ip2num = $ip1num = 0;
			$ipAddr1  = $ipAddr2 = '';
			$EndNum   = $ipAllNum;
			while ($ip1num > $ipNum || $ip2num < $ipNum) {
				$Middle = intval(($EndNum + $BeginNum) / 2);
				fseek($fd, $ipbegin + 7 * $Middle);
				$ipData1 = fread($fd, 4);
				if (strlen($ipData1) < 4) {
					fclose($fd);
					return 'System Error';
				}
				$ip1num = implode('', unpack('L', $ipData1));
				if ($ip1num < 0) $ip1num += pow(2, 32);
				if ($ip1num > $ipNum) {
					$EndNum = $Middle;
					continue;
				}
				$DataSeek = fread($fd, 3);
				if (strlen($DataSeek) < 3) {
					fclose($fd);
					return 'System Error';
				}
				$DataSeek = implode('', unpack('L', $DataSeek . chr(0)));
				fseek($fd, $DataSeek);
				$ipData2 = fread($fd, 4);
				if (strlen($ipData2) < 4) {
					fclose($fd);
					return 'System Error';
				}
				$ip2num = implode('', unpack('L', $ipData2));
				if ($ip2num < 0) $ip2num += pow(2, 32);
				if ($ip2num < $ipNum) {
					if ($Middle == $BeginNum) {
						fclose($fd);
						return 'Unknown';
					}
					$BeginNum = $Middle;
				}
			}
			$ipFlag = fread($fd, 1);
			if ($ipFlag == chr(1)) {
				$ipSeek = fread($fd, 3);
				if (strlen($ipSeek) < 3) {
					fclose($fd);
					return 'System Error';
				}
				$ipSeek = implode('', unpack('L', $ipSeek . chr(0)));
				fseek($fd, $ipSeek);
				$ipFlag = fread($fd, 1);
			}
			if ($ipFlag == chr(2)) {
				$AddrSeek = fread($fd, 3);
				if (strlen($AddrSeek) < 3) {
					fclose($fd);
					return 'System Error';
				}
				$ipFlag = fread($fd, 1);
				if ($ipFlag == chr(2)) {
					$AddrSeek2 = fread($fd, 3);
					if (strlen($AddrSeek2) < 3) {
						fclose($fd);
						return 'System Error';
					}
					$AddrSeek2 = implode('', unpack('L', $AddrSeek2 . chr(0)));
					fseek($fd, $AddrSeek2);
				} else {
					fseek($fd, -1, SEEK_CUR);
				}
				while (($char = fread($fd, 1)) != chr(0))
					$ipAddr2 .= $char;
				$AddrSeek = implode('', unpack('L', $AddrSeek . chr(0)));
				fseek($fd, $AddrSeek);
				while (($char = fread($fd, 1)) != chr(0))
					$ipAddr1 .= $char;
			} else {
				fseek($fd, -1, SEEK_CUR);
				while (($char = fread($fd, 1)) != chr(0))
					$ipAddr1 .= $char;
				$ipFlag = fread($fd, 1);
				if ($ipFlag == chr(2)) {
					$AddrSeek2 = fread($fd, 3);
					if (strlen($AddrSeek2) < 3) {
						fclose($fd);
						return 'System Error';
					}
					$AddrSeek2 = implode('', unpack('L', $AddrSeek2 . chr(0)));
					fseek($fd, $AddrSeek2);
				} else {
					fseek($fd, -1, SEEK_CUR);
				}
				while (($char = fread($fd, 1)) != chr(0))
					$ipAddr2 .= $char;
			}
			fclose($fd);
			if (preg_match('/http/i', $ipAddr2)) $ipAddr2 = '';
			$ipaddr = "$ipAddr1 $ipAddr2";
			$ipaddr = preg_replace('/CZ88\.NET/is', '', $ipaddr);
			$ipaddr = preg_replace('/^\s*/is', '', $ipaddr);
			$ipaddr = preg_replace('/\s*$/is', '', $ipaddr);
			if (preg_match('/http/i', $ipaddr) || $ipaddr == '') $ipaddr = 'Unknown';
			return $ipaddr;
		} else if (is_file(DT_ROOT . '/file/ipdata/tiny.dat')) {
			$ipdatafile = DT_ROOT . '/file/ipdata/tiny.dat';
			static $fp = NULL, $offset = array(), $index = NULL;
			$ipdot    = explode('.', $ip);
			$ip       = pack('N', ip2long($ip));
			$ipdot[0] = (int)$ipdot[0];
			$ipdot[1] = (int)$ipdot[1];
			if ($fp === NULL && $fp = @fopen($ipdatafile, 'rb')) {
				$offset = unpack('Nlen', fread($fp, 4));
				$index  = fread($fp, $offset['len'] - 4);
			} else if ($fp == false) {
				return 'Invalid IP data file';
			}
			$length = $offset['len'] - 1028;
			$start  = unpack('Vlen', $index[$ipdot[0] * 4] . $index[$ipdot[0] * 4 + 1] . $index[$ipdot[0] * 4 + 2] . $index[$ipdot[0] * 4 + 3]);
			for ($start = $start['len'] * 8 + 1024; $start < $length; $start += 8) {
				if ($index{$start} . $index{$start + 1} . $index{$start + 2} . $index{$start + 3} >= $ip) {
					$index_offset = unpack('Vlen', $index{$start + 4} . $index{$start + 5} . $index{$start + 6} . "\x0");
					$index_length = unpack('Clen', $index{$start + 7});
					break;
				}
			}
			fseek($fp, $offset['len'] + $index_offset['len'] - 1024);
			return $index_length['len'] ? fread($fp, $index_length['len']) : 'Unknown';
		} else if (is_file(DT_ROOT . '/file/ipdata/sina.dat')) {
			$sinaapi = 'http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js&ip=' . $ip;
			$ipdata  = File::get($sinaapi);
			if ($ipdata) {
				$ipdata = str_replace(array('var remote_ip_info = ', ';'), array('', ''), $ipdata);
				$arr    = json_decode($ipdata, true);
				$area   = '';
				if (isset($arr['country']) && strpos($ipdata, "\u4e2d\u56fd") === false) $area .= $arr['country'];
				if (isset($arr['province'])) $area .= $arr['province'];
				if (isset($arr['city'])) $area .= $arr['city'];
				if (isset($arr['isp'])) $area .= $arr['isp'];
				return $area ? Str::convert($area, 'UTF-8', 'GBK') : 'Unknown';
			}
			return 'API Error';
		} else {
			return $ip;
		}
	}

	/**
	 * 区域地址
	 * @param        $areaid
	 * @param string $str
	 * @param int    $deep
	 * @param int    $without
	 * @return string
	 */
	public static function pos($areaid, $str = ' &raquo; ', $deep = 0, $without = 0) {
		if ($areaid) {
			global $AREA;
		} else {
			global $L;
			return $L['allcity'];
		}
		$AREA or $AREA = PCache::read('area.php');
		$arrparentid   = $AREA[$areaid]['arrparentid'] ? explode(',', $AREA[$areaid]['arrparentid']) : array();
		$arrparentid[] = $areaid;
		$pos           = '';
		if ($deep || $without) $i = 1;
		foreach ($arrparentid as $areaid) {
			if (!$areaid || !isset($AREA[$areaid])) continue;
			if ($without) {
				if ($i == $without) {
					$i++;
					continue;
				}
			}
			if ($deep) {
				if ($i > $deep) continue;
			}
			if ($deep || $without) {
				$i++;
			}
			$pos .= $AREA[$areaid]['areaname'] . $str;
		}
		$_len = strlen($str);
		if ($str && substr($pos, -$_len, $_len) === $str) $pos = substr($pos, 0, strlen($pos) - $_len);
		return $pos;
	}

	public static function name($areaid){
		$area = self::get($areaid);
		return $area['areaname'];
	}

	public static function auth($moduleid){
		global $MG, $MODULE;
		$module = $MODULE[$moduleid]['module'];
		if (isset($MG['city_'.$module])) {
			$auth = $MG['city_'.$module];
		} else {
			$auth = -1;
		}
		return $auth;
	}

	public static function get($areaid = '', $key = ''){
		static $_cache = array();
		if (!$_cache) {
			$_cache = PCache::read('area.php');
		}
		if ($key) {
			return $_cache[$areaid][$key];
		}
		return $areaid ? $_cache[$areaid] : $_cache;
	}

	/**
	 * 单线直系亲属, 0, 1, [10]
	 * @param      $areaid
	 * @param bool $self
	 * @return array
	 */
	public static function directRelative($areaid, $self = true) {
		$_area = self::get($areaid);
		if ($areaid) {
			$directRelative = $_area['arrparentid'];
			if ($self) {
				$directRelative .= ','.$areaid;
			}
			return explode(',', $directRelative);
		} else {
			return array(0);
		}

	}

	/**
	 * 自己以及父级的所有ID, 木有 0
	 * @param $areaid
	 * @return array
	 */
	public static function directSeries($areaid){
		$_area = self::get();
		$areaids = self::directRelative($areaid, true);
		array_shift($areaids);
		$return = array();
		if ($areaids) {
			foreach($areaids as $_areaid) {
				$return[$_areaid] = $_area[$_areaid];
			}
		}
		return $return;
	}

	/**
	 * 亲朋好友, 单线联系
	 * @param $areaid
	 * @return array
	 */
	public static function relatives($areaid) {
		$directRelatives = self::directRelative($areaid);
		$return  = array();
		foreach($directRelatives as $relative) {
			$return[$relative] = self::children($relative);
		}
		return $return;
	}


	/**
	 * 所有孩子
	 * @param $areaid
	 * @return array
	 */
	public static function children($areaid) {
		$_cache = self::get();
		$return = array();
		foreach($_cache as $_areaid => $_area) {
			if ($_area['parentid'] == $areaid) {
				$return[$_areaid] = $_area;
			}
		}
		return $return;
	}

	/**
	 * 同级元素
	 * @param $areaid
	 * @return array
	 */
	public static function siblings($areaid){
		$_cache = self::get();
		if (!$_cache[$areaid]['parentid']) {
			$parentid = 0;
		} else {
			$parentid = $_cache[$areaid]['parentid'];
		}
		$return = array();
		foreach($_cache as $_areaid => $_area) {
			if ($_area['parentid'] == $parentid) {
				$return[$_areaid] = $_area;
			}
		}
		return $return;
	}

	public static function parentids($areaid, $self = true) {
		$AREA = self::get();
		$strPids = $AREA[$areaid]['arrparentid'];
		$arrPids = explode(',', $strPids);
		if ($self) {
			$arrPids[] = $areaid;
		}
		return $arrPids;
	}


	/**
	 * @param        $mod
	 * @param        $areaid
	 * @param string $join
	 * @param bool   $tripJoin
	 * @return string
	 */
	public static function position($mod, $areaid, $join = ' &nbsp; &gt; &nbsp; ', $tripJoin = false){
		$series = self::directSeries($areaid);

		$modulename = Module::info($mod,'module');

		if (!$modulename) {
			$modulename = $mod;
		}

		$return  = '';
		foreach($series as $area) {
			$return .= $join . '<a href="'.url($modulename.'/index',array('areaid'=>$area['areaid'])).'">'.$area['areaname'].'</a>';
		}
		if ($tripJoin) $return  = ltrim($return, $tripJoin);

		return $return;
	}
}